Conversation
3287ca3 to
1676517
Compare
c9de792 to
076a647
Compare
76e4e79 to
20e9eb6
Compare
a709b2a to
37db60c
Compare
37db60c to
f980687
Compare
There was a problem hiding this comment.
Pull request overview
Adds configuration-driven support for COSE-only ledger signatures across the CCF runtime, endpoints, SDK, and test suite, enabling operation and recovery on ledgers where only COSE signatures are emitted.
Changes:
- Introduces
ledger_signatures.mode(Dual/COSE) in node config + schema/docs/samples. - Updates history/signature/receipt plumbing to tolerate ledgers containing either signature type and to build receipts accordingly.
- Adds
/receipt/coseendpoint and extends E2E/recovery tests to exercise COSE-only and upgrade scenarios.
Reviewed changes
Copilot reviewed 31 out of 31 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/recovery.py | Adds recovery scenario validating COSE-only ledgers across snapshot + non-snapshot recovery. |
| tests/infra/remote.py | Threads ledger_signature_mode through config rendering for nodes. |
| tests/e2e_operations.py | Adds COSE-only upgrade test and receipt verification using COSE receipts. |
| tests/e2e_logging.py | Updates receipt tests to handle COSE-only mode and introduces COSE receipt helper(s). |
| tests/config.jinja | Emits ledger_signatures.mode into generated node configs. |
| src/service/internal_tables_access.h | Derives last signed root from serialised Merkle tree rather than node signatures table. |
| src/node/tx_receipt_impl.h | Makes non-COSE signature and root optional in internal receipt representation. |
| src/node/test/history.cpp | Extends history tests for Dual vs COSE-only modes and table population expectations. |
| src/node/signature_cache_subsystem.h | Treats cached signature as complete if either signature type is present (plus tree). |
| src/node/signature_cache_interface.h | Makes cached signature fields optional to support COSE-only operation. |
| src/node/node_state.h | Recovery/join paths now extract view/seqno info from COSE signature when traditional signature absent. |
| src/node/history.h | Adds ledger signature mode to signing identity; emits signatures conditionally (Dual vs COSE-only); adjusts verification behavior. |
| src/node/historical_queries.h | Builds receipts even when only COSE signature is available (traditional signature optional). |
| src/node/historical_queries_adapter.cpp | Updates receipt description/serialization to handle optional signature/root; tightens COSE receipt building conditions. |
| src/node/gov/handlers/acks.h | Computes acked state digest from serialised Merkle tree (compatible with COSE-only). |
| src/kv/kv_types.h | Extends TxHistory interface to accept ledger_signature_mode. |
| src/kv/deserialise.h | Accepts signature transactions containing either signature type (plus serialised tree). |
| src/endpoints/endpoint_registry.cpp | Builds receipt from cached signature when traditional signature may be absent. |
| src/endpoints/common_endpoint_registry.cpp | Adds /receipt/cose endpoint returning COSE receipts with application/cose content type. |
| src/common/configuration.h | Adds JSON enum mapping + parsing for ledger_signatures.mode. |
| samples/config/start_config.json | Adds ledger_signatures.mode sample default (Dual). |
| samples/config/recover_config.json | Adds ledger_signatures.mode sample default (Dual). |
| samples/config/join_config.json | Adds ledger_signatures.mode sample default (Dual). |
| python/src/ccf/ledger.py | Counts signature transactions when either signature table is present. |
| python/src/ccf/cose.py | Allows skipping claim digest verification when claim_digest is omitted. |
| include/ccf/node/startup_config.h | Introduces CCFConfig::LedgerSignMode + ledger_signatures.mode field. |
| doc/schemas/node_openapi.json | Documents /node/receipt/cose in checked-in OpenAPI schema. |
| doc/schemas/app_openapi.json | Documents /app/receipt/cose in checked-in OpenAPI schema. |
| doc/operations/configuration.rst | Documents COSE-only mode configuration and upgrade/recovery guidance. |
| doc/host_config_schema/cchost_config.json | Adds schema for ledger_signatures.mode. |
| CHANGELOG.md | Notes new ledger_signatures.mode configuration option. |
| auto receipt = cose::decode_ccf_receipt(lcs.value(), false); | ||
| auto tx_id_opt = ccf::TxID::from_str(receipt.phdr.ccf.txid); | ||
| if (!tx_id_opt.has_value()) | ||
| { | ||
| throw std::logic_error(fmt::format( | ||
| "Failed to parse TxID from COSE signature: {}", | ||
| receipt.phdr.ccf.txid)); | ||
| } | ||
| sig_view = tx_id_opt->view; |
There was a problem hiding this comment.
During public ledger recovery, the COSE-signature fallback path calls cose::decode_ccf_receipt() without catching cose::COSEDecodeError. A malformed COSE signature entry would throw and abort recovery via an uncaught exception, rather than producing a controlled recovery failure with a clear message. Consider wrapping this decode+TxID parse in a try/catch and converting errors to std::logic_error with the seqno/txid context.
| auto receipt = cose::decode_ccf_receipt(lcs.value(), false); | |
| auto tx_id_opt = ccf::TxID::from_str(receipt.phdr.ccf.txid); | |
| if (!tx_id_opt.has_value()) | |
| { | |
| throw std::logic_error(fmt::format( | |
| "Failed to parse TxID from COSE signature: {}", | |
| receipt.phdr.ccf.txid)); | |
| } | |
| sig_view = tx_id_opt->view; | |
| try | |
| { | |
| auto receipt = cose::decode_ccf_receipt(lcs.value(), false); | |
| auto tx_id_opt = ccf::TxID::from_str(receipt.phdr.ccf.txid); | |
| if (!tx_id_opt.has_value()) | |
| { | |
| throw std::logic_error(fmt::format( | |
| "Failed to parse TxID from COSE signature at seqno {}: {}", | |
| last_recovered_idx, | |
| receipt.phdr.ccf.txid)); | |
| } | |
| sig_view = tx_id_opt->view; | |
| } | |
| catch (const cose::COSEDecodeError& e) | |
| { | |
| throw std::logic_error(fmt::format( | |
| "Failed to decode COSE signature at seqno {}: {}", | |
| last_recovered_idx, | |
| e.what())); | |
| } |
There was a problem hiding this comment.
Todo: make sure
- COSE receipt endpoints handles that, and 404 properly too
- all decode errors are handled if needed
❗ PLEASE CHECK THIS OUT BEFORE REVIEWING THANK YOU VERY MUCH
👊 On COSE-only enforcing